package com.hengpeng.itfin.sms.impl;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URLDecoder;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.annotation.PreDestroy;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.hengpeng.common.exception.ServiceResult;
import com.hengpeng.common.persist.query.DynamicQuery;
import com.hengpeng.common.persist.query.Restrictions;
import com.hengpeng.common.persist.query.constants.QueryConstants.LockType;
import com.hengpeng.common.util.DateTimeUtil;
import com.hengpeng.itfin.service.impl.BaseServiceImpl;
import com.hengpeng.itfin.sms.SmsSendFactory;
import com.hengpeng.itfin.sms.SmsSendInnerService;
import com.hengpeng.itfin.sms.SmsSendService;
import com.hengpeng.itfinbase.persist.SmsLog;
import com.hengpeng.itfinbase.persist.SmsLog.SmsLogState;
import com.hengpeng.itfinbase.persist.SmsLog.SmsLogTransType;
import com.hengpeng.itfinbase.persist.SmsLog.SmsSendState;
import com.hengpeng.itfinbase.persist.SmsPartner;
import com.hengpeng.itfinbase.persist.SmsPartner.SmsPartnerStatus;



/**
 * <pre>
 * 短信发送服务接口实现
 * </pre>
 * @author shanguogang
 * @version 1.0, 2015-7-31
 */
@Service
@Lazy
public class SmsSendServiceImpl extends BaseServiceImpl implements SmsSendService,SmsSendInnerService
{
	Logger logger=LoggerFactory.getLogger(SmsSendServiceImpl.class); 
	protected static final ExecutorService threadPool = Executors.newCachedThreadPool();
	
	/**
	 * 2015-10-13 创蓝短信接口参数
	 */
	public static final String SMS_URL="http://222.73.117.158/msg/HttpBatchSendSM";
	public static final String SMS_USER="mohuanjr";
	public static final String SMS_PWD="Mohuan123";
	
	
	

	//到期时间，首次发送时间延后1天
	private static int expireTime=1;
	
	@PreDestroy
	public void release()
	{
		if (threadPool != null)
		{
			if (!threadPool.isShutdown())
			{
				threadPool.shutdown();
			}
		}
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED)
	public void sendNow(final String mobile, final String content, final Long partnerId, final SmsLogTransType type)
	{
		threadPool.execute(new Runnable()
		{
			@Override
			public void run()
			{
				SmsLog smsLog = new SmsLog();
				smsLog.setRetryCount(0);
				smsLog.setExpireTime(DateTimeUtil.addDate(new Date(), expireTime));
				smsLog.setContent(content);
				smsLog.setMobile(mobile);
				smsLog.setSendPriority(type.getValue());
				smsLog.setSendState(SmsSendState.IMMEDIATELY);
				smsLog.setState(SmsLogState.SENDING);
				//smsLog.setPartnerId(partnerId);
				smsLog.setTransType(type);
				serviceFactory.getApplicationContext().getBean(SmsSendInnerService.class).sendNow(smsLog);
			}
		});
	}

	
	@Override
	@Transactional(propagation = Propagation.REQUIRED)
	public void sendNow(final String mobile,final String userName, final String content, final Long partnerId, final SmsLogTransType type)
	{
		threadPool.execute(new Runnable()
		{
			@Override
			public void run()
			{
				SmsLog smsLog = new SmsLog();
				smsLog.setRetryCount(0);
				smsLog.setExpireTime(DateTimeUtil.addDate(new Date(), expireTime));
				smsLog.setContent(content);
				smsLog.setMobile(mobile);
				smsLog.setSendPriority(type.getValue());
				smsLog.setSendState(SmsSendState.IMMEDIATELY);
				smsLog.setState(SmsLogState.SENDING);
				//smsLog.setPartnerId(partnerId);
				smsLog.setUserName(userName);
				smsLog.setTransType(type);
				serviceFactory.getApplicationContext().getBean(SmsSendInnerService.class).sendNow(smsLog);
			}
		});
	}

	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public boolean sendNow(SmsLog smsLog)
	{
		boolean sendResult = false;
		smsLog.setSendTime(new Date());
		if(smsLog.getExpireTime()==null)
		{
			smsLog.setExpireTime(DateTimeUtil.addDate(new Date(), expireTime));
		}
		if(smsLog.getExpireTime().before(new Date()))
		{
			smsLog.setState(SmsLogState.FAILURE);
		}else{
			try {
				String response=batchSend(SMS_URL, SMS_USER, SMS_PWD, smsLog.getMobile(), smsLog.getContent(), true);
				String[] statusCode=getStatusCode(response);
				// 发送成功
				if("0".equals(statusCode[1])&&statusCode[2]!=null){
					logger.info("发送短信成功=="+smsLog.getMobile());
					smsLog.setState(SmsLogState.SENDED);
					smsLog.setSuccessTime(new Date());
					sendResult = true;
					
				// 额度用完
				}else if("109".equals(statusCode[1])){
					logger.info(smsLog.getMobile()+"发送短信失败== result code："+statusCode[1]);
					smsLog.setState(SmsLogState.FAILURE);
					smsLog.setMessage("额度用完");
					
					
				// 其他错误或者重发后仍未成功则发送失败
				}else if("103".equals(statusCode[1])||"104".equals(statusCode[1])){
					response=batchSend(SMS_URL, SMS_USER, SMS_PWD, smsLog.getMobile(), smsLog.getContent(), true);
					statusCode=getStatusCode(response);
					if("0".equals(statusCode[1])&&statusCode[2]!=null){
						logger.info("发送短信成功=="+smsLog.getMobile());
						smsLog.setState(SmsLogState.SENDED);
						smsLog.setSuccessTime(new Date());
						sendResult = true;
						
					}
				// 其他错误或者重发后仍未成功则发送失败
				}else if(!"103".equals(statusCode[1])&&!"104".equals(statusCode[1])&&!"0".equals(statusCode[1])){
					logger.info(smsLog.getMobile()+"发送短信失败== result code："+statusCode[1]);
					smsLog.setState(SmsLogState.FAILURE);
					if("109".equals(statusCode[1])){
						smsLog.setMessage("额度用完");
					}else{
						smsLog.setMessage("发送短信失败");
					}
					
				}
			} catch (Exception e) {
				logger.info(smsLog.getMobile()+"发送短信失败== error msg：",e);
				smsLog.setState(SmsLogState.FAILURE);
			}
			
			
			/*try{
				SmsPartner sms = serviceFactory.getDaoFactory().getCommonDao()
						.getEntity(SmsPartner.class, smsLog.getPartnerId());
				if (sms != null && sms.getStatus() == SmsPartnerStatus.OPEN)
				{
					smsLog.setSmsSendType(sms.getSmsSendType());
					ServiceResult<SmsLog> result = SmsSendFactory.getGateway(smsLog.getPartnerId()).sendMessage(smsLog);
					if (result != null)
					{
						if (result.getIsSuccess())
						{
							smsLog.setState(SmsLogState.SENDED);
							smsLog.setSuccessTime(new Date());
							sendResult = true;
						}
						else
						{
							smsLog.setState(SmsLogState.FAILURE);
							smsLog.setMessage(result.getMessage());
						}
					}
					else
					{
						smsLog.setState(SmsLogState.WAITING);
						smsLog.setMessage("短信通道调用错误");
					}
					
				}
				else
				{
					smsLog.setState(SmsLogState.FAILURE);
					smsLog.setMessage("短信通道不存在或者非开启状态");
				}
			}
			catch (Throwable ex)
			{
				logger.error("短信发送异常，短信编号{" + smsLog.getId() + "}", ex);
				smsLog.setState(SmsLogState.WAITING);
				smsLog.setMessage("短信发送异常");
			}
			//增加重发次数
			if(smsLog.getRetryCount()!=null)
			{
				smsLog.setRetryCount(smsLog.getRetryCount()+1);
			}else
			{
				smsLog.setRetryCount(1);
			}*/
		}
		if (smsLog.getId() != null)
		{
			serviceFactory.getDaoFactory().getCommonDao().updateEntity(smsLog);
		}
		else
		{
			serviceFactory.getDaoFactory().getCommonDao().saveEntity(smsLog);
		}
		return sendResult;
	}


	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public boolean sendNow(SmsLog smsLog, SmsPartner partner)
	{
		boolean sendResult = false;
		smsLog.setSendTime(new Date());
		if(smsLog.getExpireTime()==null)
		{
			smsLog.setExpireTime(DateTimeUtil.addDate(new Date(), expireTime));
		}
		if(smsLog.getExpireTime().before(new Date()))
		{
			smsLog.setState(SmsLogState.FAILURE);
		}else
		{
			try
			{
				if (partner != null && partner.getStatus() == SmsPartnerStatus.OPEN)
				{
					smsLog.setSmsSendType(partner.getSmsSendType());
					ServiceResult<SmsLog> result =  SmsSendFactory.getGateway(partner.getId()).sendMessage(smsLog);
					if (result != null)
					{
						if (result.getIsSuccess())
						{
							smsLog.setPartnerId(partner.getId());
							smsLog.setState(SmsLogState.SENDED);
							smsLog.setSuccessTime(new Date());
							sendResult = true;
						}
						else
						{
							// 明确告诉失败的,不再重发
							smsLog.setState(SmsLogState.WAITING);
							smsLog.setMessage(result.getMessage());
						}
					}
					else
					{
						smsLog.setState(SmsLogState.WAITING);
						smsLog.setMessage("短信通道调用错误");
					}
				}
				else
				{
					smsLog.setState(SmsLogState.FAILURE);
					smsLog.setMessage("短信通道不存在或者非开启状态");
				}
			}
			catch (Throwable ex)
			{
				logger.error("短信发送异常，短信编号{" + smsLog.getId() + "}", ex);
				smsLog.setState(SmsLogState.WAITING);
				smsLog.setMessage("短信发送异常");
			}
		}
		
		if (smsLog.getId() != null)
		{
			serviceFactory.getDaoFactory().getCommonDao().updateEntity(smsLog);
		}
		else
		{
			serviceFactory.getDaoFactory().getCommonDao().saveEntity(smsLog);
		}
		return sendResult;
	}

	
	
	@Override
	public void sendSystemAlarm(String content) {
		// TODO Auto-generated method stub
		
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void send(final String mobile, final String content, final Long partnerId, final SmsLogTransType type,
			final Date scheduleTime)
	{
		threadPool.execute(new Runnable()
		{
			@Override
			public void run()
			{
				SmsPartner partner = serviceFactory.getDaoFactory().getCommonDao()
						.getEntity(SmsPartner.class, partnerId);
				if (partner != null && partner.getStatus() == SmsPartnerStatus.OPEN)
				{
					SmsLog smsLog = new SmsLog();
					smsLog.setRetryCount(0);
					smsLog.setContent(content);
					smsLog.setMobile(mobile);
					smsLog.setSendPriority(type.getValue());
					if (scheduleTime != null)
					{
						smsLog.setScheduledTime(scheduleTime);
						smsLog.setExpireTime(DateTimeUtil.addDate(scheduleTime,expireTime));
						smsLog.setSendState(SmsSendState.SCHEDULED);
					}
					else
					{
						smsLog.setExpireTime(DateTimeUtil.addDate(new Date(),expireTime));
						smsLog.setSendState(SmsSendState.IMMEDIATELY);
					}
					smsLog.setState(SmsLogState.WAITING);
					smsLog.setPartnerId(partner.getId());
					smsLog.setSmsSendType(partner.getSmsSendType());
					serviceFactory.getPersistService().save(smsLog);
				}
				else
				{
					logger.error("短信通道不存在或非开启状态");
				}
			}
		});
	}

	@Transactional(propagation = Propagation.NEVER)
	public void sendJobBatch()
	{
		// 分短信渠道进行批量发.
		DynamicQuery query = new DynamicQuery(SmsPartner.class);
		query.eq("status", SmsPartnerStatus.OPEN);
		List<SmsPartner> result = serviceFactory.getPersistService().findByDynamicQuery(SmsPartner.class, query);
		for (final SmsPartner partner : result)
		{
			threadPool.execute(new Runnable()
			{
				@Override
				public void run()
				{
					List<SmsLog> result = serviceFactory.getApplicationContext().getBean(SmsSendInnerService.class)
							.lockSmsLogList(100, partner.getId());
					if (result.size() > 0)
					{
						for (final SmsLog smsLog : result)
						{
							threadPool.execute(new Runnable()
							{
								public void run()
								{
									try
									{
										serviceFactory.getApplicationContext().getBean(SmsSendInnerService.class)
												.sendNow(smsLog, partner);
									}
									catch (Throwable ex)
									{
										logger.error("发送短信异常{" + smsLog.getId() + "}", ex);
										smsLog.setState(SmsLogState.WAITING);
										smsLog.setMessage("发送短信时未知异常");
										serviceFactory.getPersistService().update(smsLog);
									}
								}
							});
						}
					}
				}
			});
		}
	}
	
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public List<SmsLog> lockSmsLogList(int size, Long partnerId)
	{
		DynamicQuery query = new DynamicQuery(SmsLog.class);
		query.eq("partnerId", partnerId);
		query.eq("state", SmsLogState.WAITING);
		query.add(Restrictions.or(
				Restrictions.eq("sendState", SmsSendState.IMMEDIATELY),
				Restrictions.and(Restrictions.eq("sendState", SmsSendState.SCHEDULED),
						Restrictions.le("scheduledTime", new Date()))));
		query.asc("retryCount");
		query.desc("sendPriority");
		query.desc("userPriority");
		query.setPageSize(size);
		List<SmsLog> result = serviceFactory.getPersistService().lockByDynamicQuery(query, SmsLog.class,
				LockType.LOCK_PASS);
		for (SmsLog log : result)
		{
			log.setState(SmsLogState.SENDING);
		}
		serviceFactory.getDaoFactory().getCommonDao().updateAllEntity(result);
		return result;
	}
 
	
	/**
	 * 2015-10-13 新增创蓝短信返回解析
	 */
	private String[] getStatusCode(String response){
		String[] result=new String[3];
		if(response!=null){
			String[] temp=response.split("\n");
			if(temp.length>=2){
				result[2]=temp[1];
			}
			String[] normalInfo=temp[0].split(",");
			result[0] =normalInfo[0];
			result[1] = normalInfo[1];
			return result;
		}else{
			return null;
		}		
	}
	
	/**
	 * 
	 * @param url 应用地址，类似于http://ip:port/msg/
	 * @param account 账号
	 * @param pswd 密码
	 * @param mobile 手机号码，多个号码使用","分割
	 * @param msg 短信内容
	 * @param needstatus 是否需要状态报告，需要true，不需要false ,请设置true获取msgId
	 * @return 返回值定义参见HTTP协议文档
	 * @throws Exception
	 */
	private String batchSend(String url, String account, String pswd, String mobile, String msg,
			boolean needstatus) throws Exception {
		HttpClient client = new HttpClient();
		PostMethod method = new PostMethod();
		try {
			URI base = new URI(url, false);
			method.setURI(new URI(base, "HttpBatchSendSM", false));
			NameValuePair[] pairs =new NameValuePair[] { 
					new NameValuePair("account", account),
					new NameValuePair("pswd", pswd), 
					new NameValuePair("mobile", mobile),
					new NameValuePair("needstatus", String.valueOf(needstatus)), 
					new NameValuePair("msg", msg)
				};
			method.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8");
			method.setRequestBody(pairs);
			int result = client.executeMethod(method);
			if (result == HttpStatus.SC_OK) {
				InputStream in = method.getResponseBodyAsStream();
				ByteArrayOutputStream baos = new ByteArrayOutputStream();
				byte[] buffer = new byte[1024];
				int len = 0;
				while ((len = in.read(buffer)) != -1) {
					baos.write(buffer, 0, len);
				}
				return URLDecoder.decode(baos.toString(), "UTF-8");
			} else {
				throw new Exception("HTTP ERROR Status: " + method.getStatusCode() + ":" + method.getStatusText());
			}
		} finally {
			method.releaseConnection();
		}

	}
	
}